/**
 * @file gis_addr_standard.h
 * @brief Brief description goes here.
 * @author silenchen
 * @version 0.1
 * @date 2013-10-17	
 * @bug
 * @warning
 * @history
 * <author>       <time>       <version>       <description>
 * @copyright Copyright 2013 Tencent Co.Ltd          
 
 */
 

#ifndef   _ERP_UTIL_CGISADDRSTANDARD_H_
#define	  _ERP_UTIL_CGISADDRSTANDARD_H_

#include <string>
#include <vector>
#include <map>
//#include <iostream>
#include "deelx.h"
#include "c2cplatform/library/basic/singleton_t.h"

namespace	erp
{
namespace	util
{

class CGisAddrStandard
{

 public:
	CGisAddrStandard()
	{
		Init();
	}
	~CGisAddrStandard()
	{
		for(std::size_t i=0;i<m_vecpReplaceSymbolRegex.size();++i)
		{
			delete m_vecpReplaceSymbolRegex[i];
		}
		delete m_pMatch1Regex;
		delete m_pMatch2Regex;
		delete m_pReplaceWhenMatch2Regex;
		delete m_pReplaceWhenNotMatch2Regex;
		delete m_pReplaceAfterMatch2Regex;
		delete m_pReplaceWhenNotMatch1AndMatch2Regex;
		delete m_pReplaceWhenNotSpecilAddr;
		delete m_pReplaceWhenNotMatch2AgainRegex;
		delete m_pMatch3Regex;
		delete m_pMatch4Regex;
		delete m_pMatch5Regex;
	}
	
	std::string& StandardAddr(
					std::string& strAddr,
					const std::string& strProvince = "",
					const std::string& strCity = "",
					const std::string& strArea = "")
	{
		//std::cout<<std::endl;
		//  全角转半角
		strAddr = ToDBC(strAddr);
		
		// remove duplicate   province  city   area
		RemoveDuplicate(strAddr,strProvince,strCity,strArea);
		
		// Replace unuseful  info
		for(std::size_t i=0;i<m_vecpReplaceSymbolRegex.size();++i)
		{
			GetReplace(m_vecpReplaceSymbolRegex[i],strAddr);
		}
		
		// 如果存在XX|弄|巷|坊，则提取其前面所有内容
		bool bMatch1 = false;
		MatchResult match1Result = m_pMatch1Regex->Match(strAddr.c_str());
		if(match1Result.IsMatched())
		{
			strAddr = strAddr.substr(match1Result.GetStart(),match1Result.GetEnd()-match1Result.GetStart());
			bMatch1 = true;
		}
	
		//如果存在XX路|街|道|XX号，则提取其前面所有内容 
		bool bMatch2 = false;
		MatchResult match2Result = m_pMatch2Regex->Match(strAddr.c_str());
		if(match2Result.IsMatched())
		{
			//std::cout<<"Ln:"<<__LINE__<<"Debug:"<<strAddr<<std::endl;
			strAddr = strAddr.substr(match2Result.GetStart(),match2Result.GetEnd()-match2Result.GetStart());
			//std::cout<<"Ln:"<<__LINE__<<"Debug:"<<strAddr<<std::endl;
			GetReplace(m_pReplaceWhenMatch2Regex,strAddr);
			//std::cout<<"Ln:"<<__LINE__<<"Debug:"<<strAddr<<std::endl;
			bMatch2 = true;
		}
		else
		{
			//std::cout<<"Ln:"<<__LINE__<<"Debug:"<<strAddr<<std::endl;

			GetReplace(m_pReplaceWhenNotMatch2Regex,strAddr);
			//std::cout<<"Ln:"<<__LINE__<<"Debug:"<<strAddr<<std::endl;
		}
		
		GetReplace(m_pReplaceAfterMatch2Regex,strAddr);
		
		//std::cout<<"Ln:"<<__LINE__<<"Debug:"<<strAddr<<" "<<bMatch1<<" "<<bMatch2<<std::endl;
		bool bNotInSpecilAddr = true;
		if(!bMatch1 && !bMatch2)
		{
			for(std::size_t i=0;i<m_vecSpecilAddr.size();++i)
			{
				std::size_t found = strAddr.find(m_vecSpecilAddr[i]);
				if(found != std::string::npos)
				{
					bNotInSpecilAddr = false;
					break;
				}
			}

			if(bNotInSpecilAddr)
				GetReplace(m_pReplaceWhenNotMatch1AndMatch2Regex,strAddr);
		}

		if(bNotInSpecilAddr)
			GetReplace(m_pReplaceWhenNotSpecilAddr,strAddr);

		if(!bMatch2)
			GetReplace(m_pReplaceWhenNotMatch2AgainRegex,strAddr);
		
		
		//搜索能作为POI的词组，并去除其后内容（分为三组优先级进行搜索）
		if(!bMatch1 && !bMatch2)
		{
			//std::cout<<"Ln:"<<__LINE__<<"Debug:"<<strAddr<<std::endl;
			bool bNotInSpecilAddr4POI = true;
			for(std::size_t i=0;i<m_vecSpecilAddr4POI.size();++i)
			{
				std::size_t found = strAddr.find(m_vecSpecilAddr4POI[i]);
				if(found != std::string::npos)
				{
					bNotInSpecilAddr4POI = false;
					break;
				}
			}

			MatchResult match3Result = m_pMatch3Regex->Match(strAddr.c_str());
			if(match3Result.IsMatched())
			{
				if(bNotInSpecilAddr4POI)
				{
					if(match3Result.MaxGroupNumber() >= 1)
					{
						strAddr = strAddr.substr(match3Result.GetGroupStart(1),match3Result.GetGroupEnd(1)-match3Result.GetGroupStart(1));
						//std::cout<<"Ln:"<<__LINE__<<"Debug:"<<strAddr<<std::endl;
					}
				}
			}
			else
			{
				//std::cout<<"Ln:"<<__LINE__<<"Debug:"<<strAddr<<std::endl;
				MatchResult match4Result = m_pMatch4Regex->Match(strAddr.c_str());
				// 需增加  city 为   深圳市  的逻辑
				if(match4Result.IsMatched())
				{
					//std::cout<<"Ln:"<<__LINE__<<"  Debug:"<<strAddr<<std::endl;
					if(bNotInSpecilAddr4POI | strCity != "深圳市")
					{
						//std::cout<<"Ln:"<<__LINE__<<"  Debug:"<<strAddr<<std::endl;
						if(match4Result.MaxGroupNumber() >= 1)
						{	
							//std::cout<<"Ln:"<<__LINE__<<"  Debug:"<<strAddr<<std::endl;
							strAddr = strAddr.substr(match4Result.GetGroupStart(1),match4Result.GetGroupEnd(1)-match4Result.GetGroupStart(1));
							//std::cout<<"Ln:"<<__LINE__<<"  Debug:"<<strAddr<<std::endl;
						}
					}
				}
				else
				{

					MatchResult match5Result = m_pMatch5Regex->Match(strAddr.c_str());
					if(match5Result.IsMatched())
					{
						if(match5Result.MaxGroupNumber() >= 1)
						{
							strAddr = strAddr.substr(match5Result.GetGroupStart(1),match5Result.GetGroupEnd(1)-match5Result.GetGroupStart(1));
						}
					}
				}
			}
			
		}
		
		// 合并 省市区  直辖市需去重
		strAddr = strArea + strAddr;
		if(strCity != strArea) strAddr = strCity + strAddr;
		if(strProvince != strCity) strAddr = strProvince + strAddr;
		
		return strAddr;
	}
private:
	void Init()
	{
		BuildDBCGroup();
		BuildSpecilAddr();
		BuildRegex();	
	}
	
	void BuildDBCGroup()
	{
		// 全角空格转半角空格
		m_DBCGroup[12288] = ' ';
		// 【 】 转  ()
		m_DBCGroup[12304] = '(';
		m_DBCGroup[12305] = ')';
		// “”    转		""
		m_DBCGroup[8220] = '\"';
		m_DBCGroup[8221] = '\"';
		// 〈〉 《》 转   <>
		m_DBCGroup[12296] = '<';
		m_DBCGroup[12297] = '>';
		m_DBCGroup[12298] = '<';
		m_DBCGroup[12299] = '>';
		//  、。  转  , .
		m_DBCGroup[12289] = ',';
		m_DBCGroup[12290] = '.';
	}
	void BuildSpecilAddr()
	{
		// specil addr
		m_vecSpecilAddr.push_back("向南东村");
		m_vecSpecilAddr.push_back("向南路");
		
		// specil addr for POI
		m_vecSpecilAddr4POI.push_back("科技园");
		m_vecSpecilAddr4POI.push_back("松涛北苑");
	}
	
	void RemoveDuplicate(
		std::string& strAddr,
		const std::string& strProvince,
		const std::string& strCity,
		const std::string& strArea)
	{
		if(!strProvince.empty())
		{
			while(1)
			{
				std::size_t pos = strAddr.find(strProvince);
				if(std::string::npos == pos)	break;
				strAddr = strAddr.erase(pos,strProvince.size());
			}
			
		}
		if(!strCity.empty())
		{
			while(1)
			{
				std::size_t pos = strAddr.find(strCity);
				if(std::string::npos == pos)	break;
				strAddr = strAddr.erase(pos,strCity.size());
			}
		}
		if(!strArea.empty())
		{
			while(1)
			{
				std::size_t pos = strAddr.find(strArea);
				if(std::string::npos == pos)	break;
				strAddr = strAddr.erase(pos,strArea.size());
			}				
		}
	}
		
	void BuildRegex()
	{
		// symbol repalce regex;	有统一的全角转半角，正则中去掉了全角字符
		m_vecpReplaceSymbolRegex.push_back(new CRegexpT<char>("(\\().*?(\\))"));
		m_vecpReplaceSymbolRegex.push_back(new CRegexpT<char>("(\").*?(\")"));
		m_vecpReplaceSymbolRegex.push_back(new CRegexpT<char>("(<).*?(>)"));

		//C#  Reg2
		m_vecpReplaceSymbolRegex.push_back(new CRegexpT<char>("((?<!\\d)\\.|,|;|\\(|\\)|\\*|(\\s+)|:)"));
		
		// logic regex				
		// C#  Reg3
		m_pMatch1Regex = new CRegexpT<char>("^.*?([0-9a-zA-Z#]|第|甲|乙|丙|丁|一|二|三|四|五|六|七|八|九|十|东|西|南|北|\\-|–|—|~)(弄|巷|坊)");
		// C#  Reg4
		m_pMatch2Regex = new CRegexpT<char>("^.*?(((路|街|道)(东|西|南|北)?([0-9a-zA-Z#]|第|甲|乙|丙|丁|一|二|三|四|五|六|七|八|九|十|\\-|–|—|~)+?(号|號|#))"
			"|((路|街|道)(东|西|南|北)?([0-9#])+)(?!栋|幢|楼|区|弄|巷|坊|米|公里|\\d|\\.))");
		// C#  Reg5	
		m_pReplaceWhenMatch2Regex = new CRegexpT<char>("([0-9a-zA-Z#]|首|第|一|二|三|四|五|六|七|八|九|十|\\-|–|—|东|南|西|北|甲|乙|丙|丁|负)+"
			"(幢|层|房(间)?|室|栋|棟|楼|单(元)?|座|档|铺(?!炕))(?!路|街|道|镇|乡|城|区|村)"
			"((东|西|南|北|甲|乙|丙|丁|负)?([0-9a-zA-Z#]|首|第|一|二|三|四|五|六|七|八|九|十|\\-|–|—)+"
			"((东|西|南|北|甲|乙|丙|丁)?(幢|棟|栋|室|门|房(间)?|(号|號)(院|楼|门|档|铺|房|间)?|楼|梯|层|单(元)?|户|座|档|铺))?)?"
			"((东|西|南|北|甲|乙|丙|丁|负)?([0-9a-zA-Z#]|首|第|一|二|三|四|五|六|七|八|九|十|\\-|–|—)+"
			"((东|西|南|北|甲|乙|丙|丁)?(幢|棟|栋|室|门|房(间)?|(号|號)(院|楼|门|档|铺|房|间)?|楼|梯|层|单(元)?|户|座|档|铺))?)?");
		// C# Reg6
		m_pReplaceWhenNotMatch2Regex = new CRegexpT<char>("([0-9a-zA-Z#]|首|第|一|二|三|四|五|六|七|八|九|十|东|南|西|北|甲|乙|丙|丁|负)+"
			"((号|號)(院|楼|门|档|铺|房|间)?|幢|层|房(间)?|室|栋|棟|楼|单元|#|\\-|–|—|座|档|铺(?!炕))(?!路|街|道|镇|乡|城|区|村)"
			"((东|西|南|北|甲|乙|丙|丁|负)?([0-9a-zA-Z#]|首|第|一|二|三|四|五|六|七|八|九|十|\\-|–|—)+"
			"((东|西|南|北|甲|乙|丙|丁)?(幢|棟|栋|室|门|房(间)?|(号|號)(院|楼|门|档|铺|房|间)?|楼|梯|层|单元|座|档|铺))?)?");
		// C# Reg9	
		m_pReplaceAfterMatch2Regex = new CRegexpT<char>("((与|和).*?交(汇|界|叉)?(口|处)?|交(汇|界|叉)?(口|处))(?!汇|界|叉|口|处)(?=.+)");
		// C# Reg8
		m_pReplaceWhenNotMatch1AndMatch2Regex = new CRegexpT<char>("(?<!路|街|道)(((斜)?对面)|(旁边)|((东|西|南|北|前|后|左|右|侧|直)(侧|面|边|行|走|入))"
			"|((往|向|以)(东|西|南|北|前|后|左|右))).*$");
		// C# Reg88
		m_pReplaceWhenNotSpecilAddr = new CRegexpT<char>("(((斜)?对面)|(旁边)|(?<!\\d|一|二|三|四|五|六|七|八|九|十|号)楼(上|下).*$|"
			"((东|西|南|北|前|后|左|右|侧|直)(侧|面|边|行|走|入)((一|二|三|四|五|六|七|八|九|十|百|\\d)+(米|m))?)|"
			"((往|向|以)(东|西|南|北|前|后|左|右)(?!路))((一|二|三|四|五|六|七|八|九|十|百|\\d)+(米|m))?|"
			"(前|后|左|右|东|南|西|北)(一|二|三|四|五|六|七|八|九|十|百|\\d)+(米|m))");
		// C# Reg7
		m_pReplaceWhenNotMatch2AgainRegex = new CRegexpT<char>("([0-9a-zA-Z#]|第|一|二|三|四|五|六|七|八|九|十|\\-|–|—|\\.|/|东|南|西|北|前|后|左|右|侧|旁|上|下|左|右|或(者)?)+$");
		
		// C# Reg10		针对售楼处增加了任意前缀的懒惰正则逻辑
		m_pMatch3Regex = new CRegexpT<char>("^(.*?((坊|所|厂(房)?|场|(学)?校(区)?|大厦|山庄|(?<!中关)村|(一|二|三|四|五|六|七|八|九|十|\\d)期)|售楼处))"
			"(?!路|街|道|镇|乡|城|区|村)(.(?!(路|街|道|镇|乡|村|城|区)))*$");
		
		// C# Reg11    区   ==>   (园|区)	公园    ====>   (晓|家|彩|雅|公|景|花|俊)园|大厦
		m_pMatch4Regex = new CRegexpT<char>("^(.*?(舍|馆|寓|院|楼|档|铺(?!炕)|局|房|站|厅|(雅|花|新)苑|(制造|生活|工业|创意|创业|产业|软件|科贸|小|社)(区|园|园区)"
			"|(汽车|物流|幼儿|科(技|学)|晓|家|彩|雅|乐|人才|公|景|花|俊|芳|豪|庭|名|桂|梅|枫|杨|竹|桃|怡|果|技术|动(漫|物)|庄|明|嘉|南)(园|園)|大厦"
			"|((工业|书|科技|车|商|电子|数码|电脑)城)|(小|中)学))(?!路|街|道|镇|乡|村|区)(.(?!(路|街|道|镇|乡|村|城|区)))*$");

        // C# Reg12
		m_pMatch5Regex = new CRegexpT<char>("^(.*?(中心|店|公司|集团|处(?!理)|社(?!区)))(?!路|街|道|镇|乡|城|区|庄)"
			"((?<!路|街|道|镇|乡|城|区|庄).(?!路|街|道|镇|乡|村|庄))*$");
	}
	
	std::string ToDBC(const std::string& strSour)
	{
		std::string strDest;
		for(std::size_t i=0;i<strSour.size();++i)
		{
			int c = strSour[i];
			if(c&0x80)
			{
				if(i+2 < strSour.size())
				{
					c = ((c&0xF)<<12)|((strSour[i+1]&0x3F)<<6)|(strSour[i+2]&0x3F);
					std::map<int,char>::iterator iter = m_DBCGroup.find(c);
					if(iter != m_DBCGroup.end())
					{
						strDest += iter->second;
					}
					else if(c > 65280 && c < 65375)
					{
						c -= 65248;
						strDest += char(c);
					}
					else
					{
						strDest += strSour[i];
						strDest += strSour[i+1];
						strDest += strSour[i+2];
					}
					i += 2;
				}
			}
			else
			{
				strDest += strSour[i];
			}
		}
		return strDest;
	}
	std::string& GetReplace(CRegexpT<char> * pRegex,std::string& strAddr)
	{
		char * szAddr = pRegex->Replace(strAddr.c_str(),"");
		strAddr = szAddr;
		if(szAddr != NULL) free(szAddr);
		return strAddr;
	}
	
private:
	std::vector<CRegexpT<char> * > m_vecpReplaceSymbolRegex;
	CRegexpT<char> * m_pMatch1Regex;
	CRegexpT<char> * m_pMatch2Regex;
	CRegexpT<char> * m_pReplaceWhenMatch2Regex;
	CRegexpT<char> * m_pReplaceWhenNotMatch2Regex;
	CRegexpT<char> * m_pReplaceAfterMatch2Regex;
	CRegexpT<char> * m_pReplaceWhenNotMatch1AndMatch2Regex;
	CRegexpT<char> * m_pReplaceWhenNotSpecilAddr;
	CRegexpT<char> * m_pReplaceWhenNotMatch2AgainRegex;
	CRegexpT<char> * m_pMatch3Regex;
	CRegexpT<char> * m_pMatch4Regex;
	CRegexpT<char> * m_pMatch5Regex;
	
	std::vector<std::string> m_vecSpecilAddr;
	std::vector<std::string> m_vecSpecilAddr4POI;
	std::map<int,char>	m_DBCGroup;
 };
 
 }
 }

typedef CSingletonT<erp::util::CGisAddrStandard, CDummyLock> CGisAddrStandardSingleton;
#define CGIS_ADDR_STANDARD			CGisAddrStandardSingleton::Instance()
 
 
 #endif  //_ERP_UTIL_GISADDRSTANDARD_H_